package gitee.cheungming.modules.governance.service;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.zaxxer.hikari.HikariDataSource;
import gitee.cheungming.modules.governance.domain.ConditionData;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.sql.*;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class ConditionService {

    @Resource(name = "tdengineDataSource")
    HikariDataSource tdengineDataSource;


    @Resource(name = "mysqlDataSource")
    HikariDataSource mysqlDataSource;

    String tablePrefix = "condition_data_";

    public String ingestion(List<ConditionData> dataList) {
        return ingestion(dataList, "tdengine");
    }

    public String ingestion(List<ConditionData> dataList, String databaseType) {
        if ("mysql".equals(databaseType)) {
            tdengineDataSource = mysqlDataSource;
        }
        int batchSize = 10000;

        String sql = "insert into data_middle_platform.dmp_condition_data" +
                " (tbname, ts, latitude, longitude, speed,vibration,direction,fuel,vin) " +
                "values (?,?,?,?,?,?,?,?,?)";
        try (Connection conn = tdengineDataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            long start = System.currentTimeMillis();
            int count = 0;
            for (ConditionData data : dataList) {
                pstmt.setString(1, tablePrefix + data.getVin());
                pstmt.setTimestamp(2, data.getTs());
                pstmt.setDouble(3, data.getLatitude());
                pstmt.setDouble(4, data.getLongitude());
                pstmt.setFloat(5, data.getSpeed());
                pstmt.setFloat(6, data.getVibration());
                pstmt.setFloat(7, data.getDirection());
                pstmt.setFloat(8, data.getFuel());
                pstmt.setString(9, data.getVin());
                pstmt.addBatch();

                if (++count % batchSize == 0) {
                    int[] batch = pstmt.executeBatch();
                    log.info("已提交: {} 条,成功：{}条", batchSize, batch.length);
                }

                if (count % 10_000 == 0) {
                    double rate = count / ((System.currentTimeMillis() - start) / 1000.0);
                    log.info("已插入:{}条, 速率{}条/秒%n", count, rate);
                }
            }

            pstmt.executeBatch();
        } catch (Exception ex) {
            log.error("Error: {}", ex.getMessage());
        }
        return "ok";
    }

    public List<ConditionData> createConditionData(long totalPoints) {
        return createConditionData(1000, totalPoints);
    }

    public List<ConditionData> createConditionData(long vehicleNumber, long totalPoints) {
        if (vehicleNumber > 1000) {
            throw new RuntimeException("车辆数不能大于1000");
        }
        final long step = 10;
        List<ConditionData> list = new ArrayList<>();
        for (int i = 0; i < vehicleNumber; i++) {
            String vin = "A".repeat(14) + String.format("%03d", i);
            for (int j = 0; j < totalPoints; j++) {
                final Instant start = Instant.parse("2025-01-01T00:00:00Z");
                Instant timestamp = start.plus(j * step, ChronoUnit.SECONDS);
                ConditionData conditionData = new ConditionData();
                conditionData.setTs(new Timestamp(timestamp.toEpochMilli()));
                conditionData.setVin(vin);
                conditionData.setLatitude(37 + RandomUtil.randomDouble(-1, 1));
                conditionData.setLongitude(120 + RandomUtil.randomDouble(-5, 5));
                conditionData.setVibration(RandomUtil.randomFloat(0, 100));
                conditionData.setSpeed(RandomUtil.randomFloat(0, 150));
                conditionData.setDirection(RandomUtil.randomFloat(0, 360));
                conditionData.setFuel(RandomUtil.randomFloat(0, 100));
                list.add(conditionData);
            }
        }

        log.info("数据条数：" + list.size());
        log.info(JSONUtil.toJsonStr(list.get(0)));
        log.info(JSONUtil.toJsonStr(list.get(list.size() - 1)));
        return list;
    }

    public ConditionData queryLatest(String vin) {
        return queryLatest(vin, "tdengine");
    }

    public ConditionData queryLatest(String vin, String databaseType) {

        String sql = "select last(ts) as ts,last(latitude) as latitude," +
                "last(longitude) as longitude,last(vibration) as vibration," +
                "last(direction) as direction,last(speed) as speed," +
                "last(fuel) as fuel, vin from data_middle_platform.dmp_condition_data where vin = ? GROUP BY vin";

        if ("mysql".equals(databaseType)) {
            tdengineDataSource = mysqlDataSource;
            sql = "SELECT ts,latitude,longitude,speed,direction,vibration,fuel,vin" +
                    " FROM data_middle_platform.dmp_condition_data WHERE vin = ? ORDER BY ts LIMIT 1";
        }
        try (Connection conn = tdengineDataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, vin);
            ResultSet resultSet = pstmt.executeQuery();
            System.out.println(sql);
            while (resultSet.next()) {
                return convert(resultSet);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("Error: {}", ex.getMessage());
        }
        throw new RuntimeException("未找到数据");
    }

    public List<ConditionData> queryHistory(String vin, Timestamp start, Timestamp end) {
        return queryHistory(vin, start, end, "tdengine");
    }

    public List<ConditionData> queryHistory(String vin, Timestamp start, Timestamp end, String databaseType) {
        List<ConditionData> list = new ArrayList<>();
        if ("mysql".equals(databaseType)) {
            tdengineDataSource = mysqlDataSource;
        }

        String sql = "select ts,latitude,longitude,vibration,direction,speed,fuel,vin" +
                " from data_middle_platform.dmp_condition_data where vin = ? and ts >=? and ts< ?";
        try (Connection conn = tdengineDataSource.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, vin);
            pstmt.setTimestamp(2, start);
            pstmt.setTimestamp(3, end);
            ResultSet resultSet = pstmt.executeQuery();
            while (resultSet.next()) {
                list.add(convert(resultSet));
            }

        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
//            System.out.println(sql);
        }
        return list;
    }

    public ConditionData convert(ResultSet resultSet) throws SQLException {
        ConditionData conditionData = new ConditionData();
        conditionData.setTs(resultSet.getTimestamp("ts"));
        conditionData.setLatitude(resultSet.getDouble("latitude"));
        conditionData.setLongitude(resultSet.getDouble("longitude"));
        conditionData.setVibration(resultSet.getFloat("vibration"));
        conditionData.setDirection(resultSet.getFloat("direction"));
        conditionData.setSpeed(resultSet.getFloat("speed"));
        conditionData.setFuel(resultSet.getFloat("fuel"));
        conditionData.setVin(resultSet.getString("vin"));
        return conditionData;
    }
}
